package context

import (
	"context"
)

// Define key types for context values to avoid conflicts
type (
	tenantKey            struct{}
	userIDKey            struct{}
	requestIDKey         struct{}
	merchantIDKey        struct{}
	tenantIsolationKey   struct{}
	merchantIsolationKey struct{}
)

// WithTenant adds tenant ID to the context
func WithTenant(ctx context.Context, tenantID string) context.Context {
	return context.WithValue(ctx, tenantKey{}, tenantID)
}

// GetTenantFromContext retrieves tenant ID from the context
func GetTenantFromContext(ctx context.Context) string {
	if ctx == nil {
		return ""
	}
	if tenantID, ok := ctx.Value(tenantKey{}).(string); ok {
		return tenantID
	}
	return ""
}

// WithUserID adds user ID to the context
func WithUserID(ctx context.Context, userID string) context.Context {
	return context.WithValue(ctx, userIDKey{}, userID)
}

// GetUserIDFromContext retrieves user ID from the context
func GetUserIDFromContext(ctx context.Context) string {
	if ctx == nil {
		return ""
	}
	if userID, ok := ctx.Value(userIDKey{}).(string); ok {
		return userID
	}
	return ""
}

// WithRequestID adds request ID to the context
func WithRequestID(ctx context.Context, requestID string) context.Context {
	return context.WithValue(ctx, requestIDKey{}, requestID)
}

// GetRequestIDFromContext retrieves request ID from the context
func GetRequestIDFromContext(ctx context.Context) string {
	if ctx == nil {
		return ""
	}
	if requestID, ok := ctx.Value(requestIDKey{}).(string); ok {
		return requestID
	}
	return ""
}

// WithMerchantID adds merchant ID to the context
func WithMerchantID(ctx context.Context, merchantID string) context.Context {
	return context.WithValue(ctx, merchantIDKey{}, merchantID)
}

// GetMerchantIDFromContext retrieves merchant ID from the context
func GetMerchantIDFromContext(ctx context.Context) string {
	if ctx == nil {
		return ""
	}
	if merchantID, ok := ctx.Value(merchantIDKey{}).(string); ok {
		return merchantID
	}
	return ""
}

// WithTenantIsolation enables or disables tenant isolation for the context
func WithTenantIsolation(ctx context.Context, enabled bool) context.Context {
	return context.WithValue(ctx, tenantIsolationKey{}, enabled)
}

// IsTenantIsolationEnabled checks if tenant isolation is enabled for the context
func IsTenantIsolationEnabled(ctx context.Context) bool {
	if ctx == nil {
		return true // 默认启用租户隔离
	}

	if enabled, ok := ctx.Value(tenantIsolationKey{}).(bool); ok {
		return enabled
	}

	return true // 默认启用租户隔离
}

// WithMerchantIsolation enables or disables merchant isolation for the context
func WithMerchantIsolation(ctx context.Context, enabled bool) context.Context {
	return context.WithValue(ctx, merchantIsolationKey{}, enabled)
}

// IsMerchantIsolationEnabled checks if merchant isolation is enabled for the context
func IsMerchantIsolationEnabled(ctx context.Context) bool {
	if ctx == nil {
		return true // 默认启用商户隔离
	}

	if enabled, ok := ctx.Value(merchantIsolationKey{}).(bool); ok {
		return enabled
	}

	return true // 默认启用商户隔离
}

// ContextInfo holds all context information
type ContextInfo struct {
	TenantID   string
	UserID     string
	RequestID  string
	MerchantID string
}

// GetContextInfo retrieves all context information
func GetContextInfo(ctx context.Context) *ContextInfo {
	return &ContextInfo{
		TenantID:   GetTenantFromContext(ctx),
		UserID:     GetUserIDFromContext(ctx),
		RequestID:  GetRequestIDFromContext(ctx),
		MerchantID: GetMerchantIDFromContext(ctx),
	}
}
